import { Injectable, Logger } from '@nestjs/common'
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'

import dayjs from 'dayjs'

import Redis from 'ioredis'

import { isNil } from 'lodash'
import { DataSource, EntityManager, LessThanOrEqual, Like, MoreThanOrEqual, Repository } from 'typeorm'

import { InjectRedis } from '~/common/decorators/inject-redis.decorator'
import { paginate } from '~/helper/paginate'
import { Pagination } from '~/helper/paginate/pagination'
import {
  AlarmStatDto,
  DashboardOverviewDto,
  DashboardQueryDto,
  DashboardStatsDto,
  DataTrendPointDto,
  DeviceStatusStatDto,
  HealthDataTrendDto,
  RecentAlarmDto,
  RegionStatDto,
} from './dashboard.dto'
import { UserDataDto, UserDataQueryDto } from './userData.dto'
import { UserDataEntity } from './userData.entity'

@Injectable()
export class UserDataService {
  private logger = new Logger(UserDataService.name)

  constructor(
    private readonly dataSource: DataSource,
    @InjectRedis() private readonly redis: Redis,
    @InjectRepository(UserDataEntity)
    private userDataRepository: Repository<UserDataEntity>,
    @InjectEntityManager() private entityManager: EntityManager,
  ) { }

  /**
   * 保存设备数据
   */
  async saveData(data: UserDataEntity[]): Promise<void> {
    await this.userDataRepository.save(data, {})
  }

  /**
   * 保存设备数据
   */
  async saveDataOne(data: UserDataEntity): Promise<void> {
    await this.userDataRepository.save(data, {})
  }

  /**
   * 数据查询
   * @param queryDto
   */
  async listData(queryDto: UserDataQueryDto): Promise<Pagination<UserDataEntity>> {
    const { page, pageSize, userId, sn, mac, name, type, uid, deptId, time } = queryDto
    const queryBuilder = this.userDataRepository
      .createQueryBuilder('data')
      .leftJoinAndSelect('data.user', 'user')
      .leftJoinAndSelect('data.device', 'device')
      .select(['data.id', 'data.userId', 'data.uid', 'data.ts', 'data.type', 'data.data', 'user.deptId', 'data.createdAt', 'user.nickname', 'device.sn'])
      .where({
        ...((!isNil(type) && type > 0) && { type }),
        ...(uid && { uid }),
        user: {
          ...(userId && { id: userId }),
          ...(deptId && { deptId }),
        },
        device: {
          ...(sn && { sn: Like(`%${sn}%`) }),
          ...(mac && { mac: Like(`%${mac}%`) }),
          ...(name && { name: Like(`%${name}%`) }),
        },
      })
      .andWhere({
        ...((time && time[0]) && { ts: MoreThanOrEqual(time[0]) }),
      })
      .andWhere({
        ...((time && time[1]) && { ts: LessThanOrEqual(time[1]) }),
      })
      .orderBy('data.ts', 'DESC')
    // this.logger.debug('queryBuilder', queryBuilder.getQueryAndParameters())
    return paginate<UserDataEntity>(queryBuilder, {
      page,
      pageSize,
    })
  }

  /**
   * 用户数据删除
   * @param id
   */
  async deleteData(id: number) {
    await this.userDataRepository.delete(id)
  }

  /**
   * 获取最新数据
   */
  async latestData({ userId }: UserDataQueryDto): Promise<UserDataDto[]> {
    const data = await this.dataSource.query(`
     ( SELECT
        type,
        MAX( ts ) ts,
        SUM( data -> '$.value' ) data
        FROM
          health_user_data 
        WHERE
          ts > ? 
          AND type IN ( 1, 2, 3 ) 
          AND user_id = ? 
        GROUP BY
          type 
      ) UNION
      (
        SELECT
          h1.type,
          h1.ts,
          h1.data -> '$.value' data 
        FROM
          health_user_data h1
          JOIN (
            SELECT
              type,
              MAX( ts ) AS max_ts 
            FROM
              health_user_data 
            WHERE
              type IN ( 7, 8, 9 ) 
              AND user_id = ? 
            GROUP BY
              type 
          ) h2 ON h1.type = h2.type 
          AND h1.ts = h2.max_ts 
        WHERE
          h1.type IN ( 7, 8, 9 ) 
          AND h1.user_id = ?)`, [dayjs().format('YYYY-MM-DD'), userId, userId, userId])

    return data as UserDataDto[]
  }

  /**
   * 获取大屏统计数据
   */
  async getDashboardStats(queryDto: DashboardQueryDto): Promise<DashboardStatsDto> {
    const { startDate, endDate, deptId, userId } = queryDto

    // 并行获取所有统计数据
    const [
      overview,
      healthTrends,
      alarmStats,
      deviceStatus,
      deptStats,
      recentAlarms,
    ] = await Promise.all([
      this.getOverviewStats(deptId, userId),
      this.getHealthTrends(startDate, endDate, deptId, userId),
      this.getAlarmStats(startDate, endDate, deptId, userId),
      this.getDeviceStatus(deptId),
      this.getDeptStats(startDate, endDate),
      this.getRecentAlarms(deptId, userId),
    ])

    return {
      overview,
      healthTrends,
      alarmStats,
      deviceStatus,
      deptStats,
      recentAlarms,
    }
  }

  /**
   * 获取总览统计数据
   */
  private async getOverviewStats(deptId?: number, userId?: number): Promise<DashboardOverviewDto> {
    const today = dayjs().format('YYYY-MM-DD')
    const sevenDaysAgo = dayjs().subtract(7, 'day').format('YYYY-MM-DD')

    // 构建部门条件
    const deptCondition = deptId ? `AND u.dept_id = ${deptId}` : ''
    const userCondition = userId ? `AND u.id = ${userId}` : ''

    const [stats] = await this.dataSource.query(`
      SELECT
        (SELECT COUNT(DISTINCT id) FROM sys_user WHERE status = 1 ${deptCondition}) as totalUsers,
        (SELECT COUNT(DISTINCT uid) FROM health_device ${deptId ? `WHERE user_id IN (SELECT id FROM sys_user WHERE dept_id = ${deptId})` : ''}) as totalDevices,
        (SELECT COUNT(DISTINCT uid) FROM health_device WHERE DATE(updated_at) = CURDATE() ${deptId ? `AND user_id IN (SELECT id FROM sys_user WHERE dept_id = ${deptId})` : ''}) as onlineDevices,
        (SELECT COUNT(*) FROM health_user_data hud 
         LEFT JOIN sys_user u ON hud.user_id = u.id
         WHERE DATE(hud.created_at) = ? ${deptCondition} ${userCondition}) as todayDataCount,
        (SELECT COUNT(*) FROM health_user_alarm hua
         LEFT JOIN sys_user u ON hua.user_id = u.id
         WHERE DATE(hua.start_at) = ? ${deptCondition} ${userCondition}) as todayAlarmCount,
        (SELECT COUNT(*) FROM health_user_alarm hua
         LEFT JOIN sys_user u ON hua.user_id = u.id
         WHERE hua.status = 0 ${deptCondition} ${userCondition}) as pendingAlarmCount,
        (SELECT COUNT(*) FROM health_user_sos hus
         LEFT JOIN sys_user u ON hus.user_id = u.id
         WHERE DATE(hus.start_at) = ? ${deptCondition} ${userCondition}) as todaySosCount,
        (SELECT COUNT(*) FROM health_user_sos hus
         LEFT JOIN sys_user u ON hus.user_id = u.id
         WHERE hus.status = 0 ${deptCondition} ${userCondition}) as pendingSosCount,
        (SELECT COUNT(DISTINCT hud.user_id) FROM health_user_data hud
         LEFT JOIN sys_user u ON hud.user_id = u.id
         WHERE hud.created_at >= ? ${deptCondition} ${userCondition}) as activeUsers
    `, [today, today, today, sevenDaysAgo])

    return {
      totalUsers: Number(stats.totalUsers) || 0,
      totalDevices: Number(stats.totalDevices) || 0,
      onlineDevices: Number(stats.onlineDevices) || 0,
      todayDataCount: Number(stats.todayDataCount) || 0,
      todayAlarmCount: Number(stats.todayAlarmCount) || 0,
      pendingAlarmCount: Number(stats.pendingAlarmCount) || 0,
      todaySosCount: Number(stats.todaySosCount) || 0,
      pendingSosCount: Number(stats.pendingSosCount) || 0,
      activeUsers: Number(stats.activeUsers) || 0,
    }
  }

  /**
   * 获取健康数据趋势（近7天或30天）
   */
  private async getHealthTrends(
    startDate?: string,
    endDate?: string,
    deptId?: number,
    userId?: number,
  ): Promise<HealthDataTrendDto[]> {
    // 默认近7天
    const start = startDate || dayjs().subtract(7, 'day').format('YYYY-MM-DD')
    const end = endDate || dayjs().format('YYYY-MM-DD')

    const deptCondition = deptId ? `AND u.dept_id = ${deptId}` : ''
    const userCondition = userId ? `AND hud.user_id = ${userId}` : ''

    // 查询心率、血压、血氧等关键指标的趋势
    // type: 1=心率, 2=血压, 3=血氧, 7=体温, 8=步数
    const trendData = await this.dataSource.query(`
      SELECT
        hud.type,
        DATE(hud.ts) as \`date\`,
        AVG(CAST(JSON_UNQUOTE(JSON_EXTRACT(hud.data, '$.value')) AS DECIMAL(10,2))) as \`avgValue\`,
        MAX(CAST(JSON_UNQUOTE(JSON_EXTRACT(hud.data, '$.value')) AS DECIMAL(10,2))) as \`maxValue\`,
        MIN(CAST(JSON_UNQUOTE(JSON_EXTRACT(hud.data, '$.value')) AS DECIMAL(10,2))) as \`minValue\`,
        COUNT(*) as \`count\`
      FROM health_user_data hud
      LEFT JOIN sys_user u ON hud.user_id = u.id
      WHERE DATE(hud.ts) BETWEEN ? AND ?
        AND hud.type IN (1, 2, 3, 7, 8)
        ${deptCondition}
        ${userCondition}
      GROUP BY hud.type, DATE(hud.ts)
      ORDER BY hud.type, DATE(hud.ts)
    `, [start, end])

    // 按类型分组
    const typeMap = new Map<number, DataTrendPointDto[]>()
    const typeNames = {
      1: '心率',
      2: '血压',
      3: '血氧',
      7: '体温',
      8: '步数',
    }

    trendData.forEach((item: any) => {
      if (!typeMap.has(item.type)) {
        typeMap.set(item.type, [])
      }
      typeMap.get(item.type)!.push({
        date: item.date,
        avgValue: Number(item.avgValue) || 0,
        maxValue: Number(item.maxValue) || 0,
        minValue: Number(item.minValue) || 0,
        count: Number(item.count) || 0,
      })
    })

    // 转换为返回格式
    return Array.from(typeMap.entries()).map(([type, trend]) => ({
      type,
      typeName: typeNames[type] || `类型${type}`,
      trend,
    }))
  }

  /**
   * 获取告警统计
   */
  private async getAlarmStats(
    startDate?: string,
    endDate?: string,
    deptId?: number,
    userId?: number,
  ): Promise<AlarmStatDto[]> {
    const start = startDate || dayjs().subtract(30, 'day').format('YYYY-MM-DD')
    const end = endDate || dayjs().format('YYYY-MM-DD')

    const deptCondition = deptId ? `AND u.dept_id = ${deptId}` : ''
    const userCondition = userId ? `AND hua.user_id = ${userId}` : ''

    const alarmData = await this.dataSource.query(`
      SELECT
        hua.type,
        COUNT(*) as count
      FROM health_user_alarm hua
      LEFT JOIN sys_user u ON hua.user_id = u.id
      WHERE DATE(hua.start_at) BETWEEN ? AND ?
        ${deptCondition}
        ${userCondition}
      GROUP BY hua.type
      ORDER BY count DESC
    `, [start, end])

    const total = alarmData.reduce((sum: number, item: any) => sum + Number(item.count), 0)

    const typeNames = {
      1: '心率异常',
      2: '血压异常',
      3: '血氧异常',
      4: '体温异常',
      5: '跌倒告警',
      6: '长时间静止',
      7: '其他异常',
    }

    return alarmData.map((item: any) => ({
      type: item.type,
      typeName: typeNames[item.type] || `类型${item.type}`,
      count: Number(item.count) || 0,
      percentage: total > 0 ? Number(((Number(item.count) / total) * 100).toFixed(2)) : 0,
    }))
  }

  /**
   * 获取设备状态统计
   */
  private async getDeviceStatus(deptId?: number): Promise<DeviceStatusStatDto> {
    const deptCondition = deptId
      ? `WHERE user_id IN (SELECT id FROM sys_user WHERE dept_id = ${deptId})`
      : ''

    const [stats] = await this.dataSource.query(`
      SELECT
        COUNT(*) as total,
        SUM(CASE WHEN DATE(updated_at) = CURDATE() THEN 1 ELSE 0 END) as online,
        SUM(CASE WHEN DATE(updated_at) < CURDATE() THEN 1 ELSE 0 END) as offline,
        SUM(CASE WHEN uid IN (SELECT DISTINCT uid FROM health_user_alarm WHERE status = 0) THEN 1 ELSE 0 END) as alarm
      FROM health_device
      ${deptCondition}
    `)

    const total = Number(stats.total) || 0
    const online = Number(stats.online) || 0
    const offline = Number(stats.offline) || 0
    const alarm = Number(stats.alarm) || 0

    return {
      online,
      offline,
      alarm,
      normal: total - alarm,
    }
  }

  /**
   * 获取部门分布统计
   */
  private async getDeptStats(startDate?: string, endDate?: string): Promise<RegionStatDto[]> {
    const start = startDate || dayjs().subtract(30, 'day').format('YYYY-MM-DD')
    const end = endDate || dayjs().format('YYYY-MM-DD')

    const deptData = await this.dataSource.query(`
      SELECT
        d.name as region,
        COUNT(DISTINCT u.id) as userCount,
        COUNT(DISTINCT hd.uid) as deviceCount,
        COUNT(DISTINCT hua.id) as alarmCount
      FROM sys_dept d
      LEFT JOIN sys_user u ON d.id = u.dept_id
      LEFT JOIN health_device hd ON u.id = hd.user_id
      LEFT JOIN health_user_alarm hua ON u.id = hua.user_id AND DATE(hua.start_at) BETWEEN ? AND ?
      GROUP BY d.id, d.name
      HAVING userCount > 0 OR deviceCount > 0
      ORDER BY userCount DESC
      LIMIT 10
    `, [start, end])

    return deptData.map((item: any) => ({
      region: item.region,
      userCount: Number(item.userCount) || 0,
      deviceCount: Number(item.deviceCount) || 0,
      alarmCount: Number(item.alarmCount) || 0,
    }))
  }

  /**
   * 获取最近告警记录
   */
  private async getRecentAlarms(deptId?: number, userId?: number): Promise<RecentAlarmDto[]> {
    const deptCondition = deptId ? `AND u.dept_id = ${deptId}` : ''
    const userCondition = userId ? `AND hua.user_id = ${userId}` : ''

    const alarms = await this.dataSource.query(`
      SELECT
        hua.id,
        u.nickname as userName,
        hua.type,
        hua.content,
        hua.status,
        hua.start_at as startAt,
        hd.sn as deviceSn
      FROM health_user_alarm hua
      LEFT JOIN sys_user u ON hua.user_id = u.id
      LEFT JOIN health_device hd ON hua.uid = hd.uid
      WHERE 1=1
        ${deptCondition}
        ${userCondition}
      ORDER BY hua.start_at DESC
      LIMIT 10
    `)

    return alarms.map((item: any) => ({
      id: item.id,
      userName: item.userName,
      type: item.type,
      content: item.content,
      status: item.status,
      startAt: item.startAt,
      deviceSn: item.deviceSn,
    }))
  }
}
